package com.yauthor.module
{
	import mx.utils.object_proxy;

	public class Result implements IStatefull
	{
		private var _result:SimpleResult
		private var _mappedResult:SimpleResult
		private var _mapped:Boolean
		
		private var _resultCountMode:ResultCountMode;
		
		public function Result(todo:uint = 0, done:uint = 0, errors:uint = 0 , includeErrorsInResult:Boolean = true, evalPending:Boolean = false)
		{			
			_result = new SimpleResult(todo,done,errors,includeErrorsInResult,evalPending);
			_mapped = false
			resultCountMode = ResultCountMode.FLOOR;
		}
		
		public function saveState(saveStateContext:IStateSaveContext):void
		{	
			_result.saveState(saveStateContext)
			if(_mapped == true)
				_mappedResult.saveState(saveStateContext)
		}
		
		public function loadState(loadStateContext:IStateLoadContext):void
		{
			_result.loadState(loadStateContext)
			_mapped = loadStateContext.dataInput.bytesAvailable > 0;
			if(_mapped == true){
				if(!_mappedResult)
					_mappedResult = createSimpleResult(this, false);
				_mappedResult.loadState(loadStateContext);
			}
		}
		
		/**
		 * Activity awaits for evaluation.
		 */
		public function get evaluationPending():Boolean{
			return _result.evaluationPending;
		}
		
		public function get includeErrorsInResult():Boolean {			
			
			return _result.includeErrorsInResult
			
		}
		
		/**
		 * How many elements user should do. <br> 
		 * WARNING: done + errors can be different than todo
		 */
		public function get todo():uint{
			return _result.todo
		}
		
		/**
		 * How many points user should do. <br> 
		 * WARNING: points done +  points errors can be different than todo
		 */
		public function get todoPoints():uint{
			return _mapped == true ? _mappedResult.todo : this.todo
		}
		
		
		/**
		 * How many activity elements were done correctly. Elements
		 * that were not touched by counted as done nor as errors. 
		 */
		public function get done():uint{
			return _result.done	
		}
		
		/**
		 * How many activity elements were done correctly after mapping. Elements
		 * that were not touched by counted as done nor as errors. 
		 */
		public function get donePoints():uint{
			return _mapped == true ? _mappedResult.done : this.done		
		}		
		
		
		/**
		 * How many activity elements were done incorrectly.
		 */
		public function get errors():uint{
			return _result.errors
		}
		
		
		/**
		 * How many activity elements were done incorrectly afrer mapping.
		 */
		public function get errorsPoints():uint{
			return _mapped == true ? _mappedResult.errors : this.errors
		}
		/**
		 * A number of errors that will be substracted from the result. Not all
		 * errors may take part in result counting - it is configured externally.  
		 */
		public function get errorsInResult():uint{
			return _result.errorsInResult
		}
		/**
		 * The percentage result calculated on todo/done/errors. The result is rounded
		 * downwards (floor) to whole numbers.
		 * @return percentage result or Number.POSITIVE_INFINITY if there is nothing todo
		 * in this result
		 */
		public function get result():Number{
			return _result.result
		}
		
		
		/**
		 * The percentage result calculated on todoPoints/donePoints/errorPoints. The result is rounded
		 * downwards (floor) to whole numbers.
		 * @return percentage result or Number.POSITIVE_INFINITY if there is nothing todo
		 * in this result
		 */
		public function get resultPoints():Number{
			return _mapped == true ? _mappedResult.result : this.result;
		}
		/**
		 * Check if this result is equal to some other result.
		 * @param r other result
		 * @return true if results are equal
		 */
		public function equals( r:Result ):Boolean{
			var sr:SimpleResult = createSimpleResult(r);
			var res:Boolean = _result.equals(sr);
			
			if(res == true){
				res = (r.todoPoints == todoPoints && r.donePoints == donePoints && r.errorsPoints == errorsPoints) 
			}
			
			return res;
		}
		
		public function append( r:Result ):void {
			var sr:SimpleResult = createSimpleResult(r);
			
			if(r.mapped == true || _mapped == true){
				if(_mapped == false)
					initMappedResult(this,false);
				
				var mapped:SimpleResult = createSimpleResult(r,true);
				_mappedResult.append(mapped)
			}			
			
			_result.append(sr);
		}
		
		public function get errorsUncounted():Number{
			return _result.errorsUncounted
		}
		
		public function initMappedResult(r:Result,mapped:Boolean = false):void{			
			_mappedResult = createSimpleResult(r,mapped);
			_mapped = true
		}
		
		public function get mapped():Boolean{
			return _mapped;
		}
		
		public function set resultCountMode(value:ResultCountMode):void{
			_resultCountMode = value;
			
			if(_mappedResult != null)
				_mappedResult.resultCountMode = value;
			
			if(_result != null)
				_result.resultCountMode = value;
		}
		
		
		private function createSimpleResult(r:Result,mapped:Boolean = false):SimpleResult{
			var sr:SimpleResult = new SimpleResult();
			sr.initFromResult(r,mapped);
			sr.resultCountMode = _resultCountMode;
			return sr;
		}		
		
	}
}